package entity;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.TimeZone;

/**
 * Values and methods for specifying the RRULE property
 * for the iCalendar object as defined in RFFC 5545. This
 * property defines a rule or repeating pattern for recurring
 * events.
 * 
 * @author Sean Young
 * @version 1.0
 *
 */
public class RecurrenceRule implements EntityConstants{
	private int frequency;
	private int count;
	private int interval;
	private String byDay;
	private String byMonthDay;
	private String byMonth;
	private String until;
	
	/**
	 * Constructor for the RRULE property. All values are defaulted
	 * to null. A value of -1 indicates the exclusion of an integer
	 * property.
	 */
	public RecurrenceRule() {
		frequency = -1;
		count = -1;
		interval = -1;
		byDay = null;
		until = null;
	}
	
	/**
	 * Adds a FREQ property to the RRULE with the specified
	 * frequency.
	 * @param frequency The frequency of the Event.
	 *                  1 = DAILY, 2 = WEEKLY, 3 = MONTHLY, 4 = YEARLY
	 *                  As defined in EntityConstants.java
	 */
	public void addFrequency(int frequency) {
		this.frequency = frequency;
	}
	
	/**
	 * Adds a COUNT property to the RRULE with the specified
	 * count. The count is the number of times the event will
	 * be repeated.
	 * @param count The number of times the event will be repeated.
	 */
	public void addCount(int count) {
		this.count = count;
	}
	
	/**
	 * Adds an INTERVAL property to the RRULE with the specified
	 * interval. The interval indicates the period between the 
	 * occurrence of an event. The length of this period is
	 * determined by the frequency (FREQ).
	 * @param interval The interval in between occurrences
	 */
	public void addInterval(int interval) {
		this.interval = interval;
	}
	
	/**
	 * Adds a BYDAY property to the RRULE with the specified days.
	 * The BYDAY property determines which days of the week the 
	 * recurrence events will take place on. 
	 * @param days An ArrayList containing the days the event will
	 *             occur. [SUN-SAT]
	 */
	public void addByDay(ArrayList<String> days) {
		StringBuilder byDayBuilder = new StringBuilder();
		for(int i = 0; i < days.size(); i++) {
			byDayBuilder.append(days.get(i));
			if((days.size() != 1) && (i != days.size() - 1)) byDayBuilder.append(",");
		}
		this.byDay = byDayBuilder.toString();
	}
	
	/**
	 * Adds a BYMONTHDAY property to the RRULE with the specified days.
	 * The BY BYMONTHDAY property determines which days of the month 
	 * the recurrence events will take place on. 
	 * @param days An ArrayList containing the days the event will
	 *             occur. [1-31]
	 */
	public void addByMonthDay(ArrayList<String> days) {
		StringBuilder byMonthDayBuilder = new StringBuilder();
		for(int i = 0; i < days.size(); i++) {
			byMonthDayBuilder.append(days.get(i));
			if((days.size() != 1) && (i != days.size() - 1)) byMonthDayBuilder.append(",");
		}
		this.byMonthDay = byMonthDayBuilder.toString();
	}
	
	/**
	 * Adds a BYMONTH property to the RRULE with the specified months.
	 * The BY BYMONTH property determines which months of the year 
	 * the recurrence events will take place on. 
	 * @param months An ArrayList containing the days the event will
	 *             occur. [JAN-DEC]
	 */
	public void addByMonth(ArrayList<String> months) {
		StringBuilder byMonthBuilder = new StringBuilder();
		for(int i = 0; i < months.size(); i++) {
			byMonthBuilder.append(months.get(i));
			if((months.size() != 1) && (i != months.size() - 1)) byMonthBuilder.append(",");
		}
		this.byMonth = byMonthBuilder.toString();
	}
	
	/**
	 * Adds an UNTIL property to the RRULE with the specified months.
	 * The UNTIL property determines the date at which the event will
	 * stop recurring. 
	 * @param d The date at which the Recurrence events will end
	 */
	public void addUntil(Date d) {
		SimpleDateFormat dForm = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
		dForm.setTimeZone(TimeZone.getTimeZone("GMT"));
		this.until = dForm.format(d);
	}
	
	/**
	 * Returns a string containing the values of the fields of the
	 * RRULE. Fields that were not added to the RRULE will not be included. 
	 * @return A String containing a properly formatted RRULE property.
	 */
	public String toString() {
		StringBuilder rruleString = new StringBuilder("RRULE:");
		
		if(frequency > -1) {
			switch(frequency) {
			case FREQUENCY_DAILY:   rruleString.append("FREQ=DAILY;");
									break;
			case FREQUENCY_WEEKLY:  rruleString.append("FREQ=WEEKLY;");
									break;
			case FREQUENCY_MONTHLY: rruleString.append("FREQ=MONTHLY;");
									break;
			case FREQUENCY_YEARLY:  rruleString.append("FREQ=YEARLY;");
									break;
			
			}
		}
		
		if(interval > -1) {
			rruleString.append("INTERVAL=");
			rruleString.append(interval);
			rruleString.append(";");
		}
		
		if(count > -1) {
			rruleString.append("COUNT=");
			rruleString.append(count);
			rruleString.append(";");
		}
		
		if(byDay != null) {
			rruleString.append("BYDAY=");
			rruleString.append(byDay);
			rruleString.append(";");
		}
		
		if(byMonthDay != null) {
			rruleString.append("BYMONTHDAY=");
			rruleString.append(byMonthDay);
			rruleString.append(";");
		}
		
	    if(byMonth != null) {
	    	rruleString.append("BYMONTH=");
			rruleString.append(byMonth);
			rruleString.append(";");
	    }
		
		if(until != null) {
			rruleString.append("UNTIL=");
			rruleString.append(until);
			rruleString.append(";");
		}
		
		rruleString.setLength(rruleString.length() - 1); // Remove last ';'
		rruleString.append("\r\n");
		
		return rruleString.toString();
	}

}
